// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package typecheck

import (
	"cmd/compile/internal/base"
	"cmd/compile/internal/ir"
	"cmd/compile/internal/types"
	"cmd/internal/obj"
	"cmd/internal/src"
)

func LookupRuntime(name string) *ir.Name {
	s := ir.Pkgs.Runtime.Lookup(name)
	if s == nil || s.Def == nil {
		base.Fatalf("LookupRuntime: can't find runtime.%s", name)
	}
	return ir.AsNode(s.Def).(*ir.Name)
}

// 子参数类型将给定的类型列表替换为
// 连续出现在
// 类型语法表达式n.type中的“any”占位符。
// 子参数类型的结果必须重新分配到旧的，例如
// n.Left=subStragtypes（n.Left，t1，t2）
func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
	for _, t := range types_ {
		types.CalcSize(t)
	}
	n := ir.NewNameAt(old.Pos(), old.Sym())
	n.Class = old.Class
	n.SetType(types.SubstAny(old.Type(), &types_))
	n.Func = old.Func
	if len(types_) > 0 {
		base.Fatalf("SubstArgTypes: too many argument types")
	}
	return n
}

// 自动标签生成一个新的名称节点，用于
// 自动生成的标签。
// 前缀是一个简短的助记符（例如，“.s”代表开关）
// 用于帮助调试。
// 应该以“.”开头避免与
// 用户标签冲突。
func AutoLabel(prefix string) *types.Sym {
	if prefix[0] != '.' {
		base.Fatalf("autolabel prefix must start with '.', have %q", prefix)
	}
	fn := ir.CurFunc
	if ir.CurFunc == nil {
		base.Fatalf("autolabel outside function")
	}
	n := fn.Label
	fn.Label++
	return LookupNum(prefix, int(n))
}

func Lookup(name string) *types.Sym {
	return types.LocalPkg.Lookup(name)
}

// InitRuntime加载低级运行时函数的定义，
// 以便编译器可以生成对它们的调用，但不会使它们对用户代码可见。
func InitRuntime() {
	base.Timer.Start("fe", "loadsys")
	types.Block = 1

	typs := runtimeTypes()
	for _, d := range &runtimeDecls {
		sym := ir.Pkgs.Runtime.Lookup(d.name)
		typ := typs[d.typ]
		switch d.tag {
		case funcTag:
			importfunc(src.NoXPos, sym, typ)
		case varTag:
			importvar(src.NoXPos, sym, typ)
		default:
			base.Fatalf("unhandled declaration tag %v", d.tag)
		}
	}
}

// LookupRuntimeFunc在包运行时查找Go函数名。此函数
// 必须遵循内部调用约定。
func LookupRuntimeFunc(name string) *obj.LSym {
	return LookupRuntimeABI(name, obj.ABIInternal)
}

// LookupRuntimeVar在包
// runtime中查找变量（或汇编函数）名称。如果这是一个函数，它可能有一个特殊的调用
// 约定。
func LookupRuntimeVar(name string) *obj.LSym {
	return LookupRuntimeABI(name, obj.ABI0)
}

// LookupRuntimeABI使用给定的ABI在包运行时查找名称。
func LookupRuntimeABI(name string, abi obj.ABI) *obj.LSym {
	return base.PkgLinksym("runtime", name, abi)
}
